package saintseiya.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.LinkedList;
import java.util.Properties;

import javax.swing.JFileChooser;

import saintseiya.view.MainFrame;

/**
 * Extracts TIM2/TIM3 images from uncompresses binary files into separate files.
 */
public class BinaryTimExtractor {

	public static void main(String[] args) throws IOException {
		// initialize properties with default value
		Properties props = new Properties();
		props.setProperty(MainFrame.LAST_DIR_KEY, MainFrame.DEFAULT_LAST_DIR);
		// try to load values from file
		try {
			props.load(new FileReader(MainFrame.PROP_FILE));
		}
		catch(IOException ioe) {}


		// file chooser to choose the folder
		JFileChooser chooser = new JFileChooser();
		chooser.setDialogTitle("Select binary file containing TIM images");
		chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
		chooser.setCurrentDirectory(new File(props.getProperty(MainFrame.LAST_DIR_KEY)));
		int returnVal = chooser.showOpenDialog(null);

		// if folder selected
		if (returnVal == JFileChooser.APPROVE_OPTION) {
			File binaryFile = chooser.getSelectedFile();
			if (binaryFile.exists() && binaryFile.canRead() && binaryFile.isFile()) {
				// update the properties file
				props.setProperty(MainFrame.LAST_DIR_KEY, binaryFile.getParentFile().getAbsolutePath());
				props.store(new FileWriter(MainFrame.PROP_FILE), null);

				extractTimImages(binaryFile);
			}
		}
	}

	private static void extractTimImages(File binaryFile) throws FileNotFoundException, IOException {
		InputStream is = new FileInputStream(binaryFile);
		OutputStream os = null;
		int offsetCount = 0;
		int imageCount = 0;

		LinkedList<Integer> buffer = new LinkedList<Integer>();
		buffer.add(-1);
		buffer.add(-1);
		buffer.add(-1);
		buffer.add(-1);

		int readByte;
		// get rid of the initial non image bytes
		while( (readByte = is.read()) != -1 ) {
			++offsetCount;
			// shift the buffer
			buffer.removeFirst();
			buffer.addLast( readByte );
			if( isTimHeader(buffer) ) {
				// reached the first image
				os = new FileOutputStream(new File(binaryFile.getParent(), String.format("%04d_%06x", ++imageCount, offsetCount - 3) + ".tm2"));
				break;
			}
		}

		while( (readByte = is.read()) != -1 ) {
			++offsetCount;
			// shift the buffer
			os.write(buffer.removeFirst());
			buffer.addLast( readByte );
			if( isTimHeader(buffer) ) {
				// reached the end of current image
				os.flush();
				os.close();
				// prepares the next image
				os = new FileOutputStream(new File(binaryFile.getParent(), String.format("%04d_%06x", ++imageCount, offsetCount - 3) + ".tm2"));
			}
		}

		// write the remaining bytes from buffer
		if( os != null ) {
			for( int b : buffer ) {
				os.write(b);
			}
			os.flush();
			os.close();
		}
	}

	private static boolean isTimHeader(LinkedList<Integer> buffer) {
		return buffer.size() >= 4 &&
		buffer.get(0) == 0x54 && // T
		buffer.get(1) == 0x49 && // I
		buffer.get(2) == 0x4d && // M
		(buffer.get(3) == 0x32 || // 2
		buffer.get(3) == 0x33); // or 3
	}
}
